--[[
	Ikarus Unit-Frames Addon	
	released under GNU General Public License version 3 (GPLv3) 
	by McGaerty & Sl4ker
	
	contact: mcgaerty@ikarus-systems.net rom@sl4ker.de	
	download: http://rom.curse.com/downloads/rom-addons/details/ikarus-unitframes.aspx
	
	special thanks to Qwox and novayuna for inspiration and stable basics
]]



local ikarus = _G["ikarus"];


ikarus.profileManager = {};
ikarus.profileManager.presets = {};

ikarus.profileManager.FRAME = "Ikarus_ProfileManager";

function ikarus.profileManager:IsInitialised()
	return self.initialised == true;
end;

function ikarus.profileManager:Initialise()
	if(not self:IsInitialised()) then
	
		--  WORKAROUND
		RunScript("SYS_DisplaySettings_Frame:Show()");		
		Ikarus_EventFrame.configX, Ikarus_EventFrame.configY = SYS_DisplaySettings_Frame:GetPos();
		RunScript("SYS_DisplaySettings_Frame:SetPos(-"..SYS_DisplaySettings_Frame:GetWidth()..",0)");
		Ikarus_EventFrame.delay = 1;
		
		self:RegisterUpdater(1.0, ikarus.profileManager.UPDATER_1_0);
		
		UIDropDownMenu_SetWidth(getglobal(self.FRAME .. "ImportFrameDropDown"), 230);
		UIDropDownMenu_SetWidth(getglobal(self.FRAME .. "ImportFrameResolutionDropDown"), 100);
		UIDropDownMenu_SetWidth(getglobal(self.FRAME .. "DeleteFrameDropDown"), 230);
		
		local file = ikarus.constants["ADDON_DIR"] .. "profiles/_index.lua";
		_,self.presets = ikarus:LoadFile(file);
		if(type(self.presets) ~= "table") then
			self.presets = {{"Default","default_1280x1024",1280,1024}};
		end;
		
		self.initialised = true;
	end;
end;

function ikarus.profileManager:RegisterUpdater(version, updater)
	if not(self.updaters) then
		self.updaters = {};
	end;
	local key = string.format("%.1f", version);
	if not(self.updaters[key]) then
		self.updaters[key] = updater;
	end;
end;

function ikarus.profileManager:ImportProfile(profile, imports, resolution)
	if(profile and imports and resolution) then
		--ikarus:SetDelegatesEnabled(false);
		
		if(profile.RESOLUTION) then
			local transformation = self:CreateTransformation(profile.RESOLUTION, resolution);
			
			--  Transform all units
			self:TransformUnitProfile(profile, "player", transformation);
			self:TransformUnitProfile(profile, "target", transformation);
			self:TransformUnitProfile(profile, "targettarget", transformation);
			self:TransformUnitProfile(profile, "targettargettarget", transformation);
			self:TransformUnitProfile(profile, "party", transformation);
			self:TransformUnitProfile(profile, "partytarget", transformation);
			self:TransformUnitProfile(profile, "playercastbar", transformation);
			self:TransformUnitProfile(profile, "targetcastbar", transformation);
		end;
		
		local latestVersion = tonumber(ikarus.config.defaults.VARIABLES_VERSION);
		if not(self:UpdateProfile(latestVersion, profile, resolution)) then
			return false;
		end;
				
		local unit;
		for idx = 1,#imports do
			unit = imports[idx];
			--ikarus.debug:Print("importing unit: "..unit);
			ikarus.profile[unit] = nil;
			ikarus.profile[unit] = profile[unit];
		end;
		
		ikarus.profile.RESOLUTION = resolution;
		ikarus.profile.global.GENERAL.PROFILE = ikarus:GetProfileName();
		ikarus.profile.VARIABLES_VERSION = string.format("%.1f", latestVersion);
				
		ikarus.config:SaveProfile();
		
		ikarus:LoadConfigOnUnitDelegates();
		ikarus:SetDummyState(false);
		ikarus:SetDummyState(true);
		--ikarus:GetDelegate("global"):LoadConfig();
		
		--ikarus:SetDelegatesEnabled(true);
		return true;
	end;
end;

function ikarus.profileManager:UpdateProfile(latestVersion, profile, resolution)
	if not(latestVersion and profile and latestVersion > 0) then
		return;
	end;
	
	local newVersion, updater, key;
	local valid = true;
	local transformation;
	if(resolution) then
		transformation = ikarus.profileManager:CreateTransformation(ikarus.config.defaults.RESOLUTION, resolution);
	end;
	while (tonumber(profile.VARIABLES_VERSION) < tonumber(latestVersion) and valid) do
		key = string.format("%.1f", tonumber(profile.VARIABLES_VERSION));
		updater = self.updaters[key];
		if(updater) then
			newVersion = updater(profile, transformation);
			if(newVersion) then
				profile.VARIABLES_VERSION = string.format("%.1f", newVersion);
			else
				valid = false;
			end;
		else
			valid = false;
		end;
	end;
	
	return valid;
end;

function ikarus.profileManager.UPDATER_1_0(profile, transformation)
	--[[
		New entries:
		
		targetcastbar
		global.GENERAL.USE_GLOBAL_TEXTURE
		global.GENERAL.GLOBAL_TEXTURE
		RESOLUTION (not required)
	]]
	
	if(profile) then
		profile.targetcastbar = ikarus.utils:TableClone(ikarus.config.defaults.targetcastbar);
		if(transformation) then
			ikarus.profileManager:TransformUnitProfile(profile, "targetcastbar", transformation);
		end;
		--profile.RESOLUTION = {x = 1280, y = 1024};	
		profile.global.GENERAL.USE_GLOBAL_TEXTURE = ikarus.config.defaults.global.GENERAL.USE_GLOBAL_TEXTURE;
		profile.global.GENERAL.GLOBAL_TEXTURE = ikarus.config.defaults.global.GENERAL.GLOBAL_TEXTURE;

		return 1.1;
	end;
end;

--  create a transformation table used to transform profiles
function ikarus.profileManager:CreateTransformation(resFrom, resTo)
	local transformation = {
		ratioX = resTo.x/resFrom.x,
		ratioY = resTo.y/resFrom.y,
		oldWidth = resFrom.x,
		oldHeight = resFrom.y,
		newWidth = resTo.x,
		newHeight = resTo.y,
		minScale = 0.5,
		maxScale = 2.0,
		minFontsize = 6,
		maxFontsize = 20
	};
	transformation.maxRatio = math.max(transformation.ratioX, transformation.ratioY);
	transformation.minRatio = math.min(transformation.ratioX, transformation.ratioY);
	return transformation;
end;

function ikarus.profileManager:TransformUnitProfile(profile, unit, transformation)
	if(profile[unit]) then
		self:Transform(profile, unit, "GENERAL", "WIDTH", transformation.ratioX);
		self:Transform(profile, unit, "GENERAL", "HEIGHT", transformation.ratioY);
		self:Transform(profile, unit, "GENERAL", "OFFSET_X", transformation.ratioX);
		self:Transform(profile, unit, "GENERAL", "OFFSET_Y", transformation.ratioY);
		self:Transform(profile, unit, "GENERAL", "SPACING", transformation.minRatio);
		
		self:TransformFont(profile, unit, "LABELS", "TOPTEXT_FONTSIZE", transformation);
		self:TransformFont(profile, unit, "LABELS", "RIGHTTEXT_FONTSIZE", transformation);
		self:TransformFont(profile, unit, "LABELS", "LEFTTEXT_FONTSIZE", transformation);
		self:TransformFont(profile, unit, "LABELS", "BOTTOMTEXT_FONTSIZE", transformation);
		
		self:TransformBuffProfile(profile, unit, "BUFFS", transformation);
		self:TransformBuffProfile(profile, unit, "DEBUFFS", transformation);
		
		self:TransformIconProfile(profile, unit, "RAIDLEADER", transformation);
		self:TransformIconProfile(profile, unit, "CHANNEL", transformation);
		self:TransformIconProfile(profile, unit, "RAIDTARGET", transformation);
		self:TransformIconProfile(profile, unit, "PVPSTATE", transformation);
		self:TransformIconProfile(profile, unit, "LOOTER", transformation);
		self:TransformIconProfile(profile, unit, "BOSS", transformation);
		self:TransformIconProfile(profile, unit, "MAINCLASS", transformation);
		self:TransformIconProfile(profile, unit, "SUBCLASS", transformation);
		self:TransformIconProfile(profile, unit, "DISCONNECT", transformation);
	
		self:TransformBarProfile(profile, unit, "HEALTHBAR", transformation);
		self:TransformBarProfile(profile, unit, "MANABAR", transformation);
		self:TransformBarProfile(profile, unit, "SKILLBAR", transformation);
		self:TransformBarProfile(profile, unit, "PROGRESSBAR", transformation);
		
		self:TransformSubframeProfile(profile, unit, "PORTRAIT", transformation);
		
		self:TransformDockingProfile(profile, unit, transformation);
	end;
end;

function ikarus.profileManager:TransformBarProfile(profile, unit, bar, transformation)
	if(profile[unit][bar]) then
		self:TransformFont(profile, unit, bar, "LEFTTEXT_FONTSIZE", transformation);
		self:TransformFont(profile, unit, bar, "RIGHTTEXT_FONTSIZE", transformation);
		self:TransformFont(profile, unit, bar, "OUTSIDE_LEFTTEXT_FONTSIZE", transformation);
		self:TransformFont(profile, unit, bar, "OUTSIDE_RIGHTTEXT_FONTSIZE", transformation);
	end;
end;

function ikarus.profileManager:TransformSubframeProfile(profile, unit, frame, transformation)
	if(profile[unit][frame]) then
		self:TransformScale(profile, unit, frame, "SCALE", transformation);
	end;
end;

function ikarus.profileManager:TransformIconProfile(profile, unit, prefix, transformation)
	if(profile[unit].ICONS) then
		if(ikarus.utils:IsValidString(prefix)) then
			prefix = prefix.."_";
		else
			prefix = "";
		end;
		self:TransformScale(profile, unit, "ICONS", prefix.."SCALE", transformation);
	end;
end;

function ikarus.profileManager:TransformBuffProfile(profile, unit, prefix, transformation)
	if(profile[unit].BUFFS) then
		if(ikarus.utils:IsValidString(prefix)) then
			prefix = prefix.."_";
		else
			prefix = "";
		end;
		self:TransformScale(profile, unit, "BUFFS", prefix.."SCALE", transformation);
		self:TransformFont(profile, unit, "BUFFS", prefix.."FONTSIZE", transformation);
	end;
end;

function ikarus.profileManager:TransformDockingProfile(profile, unit, transformation)
	if(profile[unit].DOCKING) then
		self:Transform(profile, unit, "DOCKING", "OFFSET_X", transformation.ratioX);
		self:Transform(profile, unit, "DOCKING", "OFFSET_Y", transformation.ratioY);
	end;
end;

function ikarus.profileManager:TransformFont(profile, unit, child, property, transformation)
	if(profile[unit][child][property]) then
		local s;
		if(transformation.minRatio < 1.0) then
			s = math.floor(tonumber(profile[unit][child][property]) * transformation.minRatio * 1.4);
		else
			s = math.floor(tonumber(profile[unit][child][property]) * transformation.minRatio * 0.8);
		end;
		if(s < transformation.minFontsize) then
			s = transformation.minFontsize;
		elseif(s > transformation.maxFontsize) then
			s = transformation.maxFontsize;
		end;
		profile[unit][child][property] = s;
	end;
end;

function ikarus.profileManager:TransformScale(profile, unit, child, property, transformation)
	if(profile[unit][child][property]) then
		local s = tonumber(profile[unit][child][property]) * transformation.minRatio;
		if(s < transformation.minScale) then
			s = transformation.minScale;
		elseif(s > transformation.maxScale) then
			s = transformation.maxScale;
		end;
		profile[unit][child][property] = s;
	end;
end;

function ikarus.profileManager:Transform(profile, unit, child, property, ratio)
	--ikarus.debug:Print(tostring(unit).." "..tostring(child).." "..tostring(property).." "..tostring(ratio));
	if(profile[unit][child][property]) then
		profile[unit][child][property] = tonumber(profile[unit][child][property]) * ratio;
	end;
end;


function ikarus.profileManager:IsVisible()
	return getglobal(self.FRAME):IsVisible();
end;

function ikarus.profileManager:ShowConfigFrame()
	if not(self:IsVisible()) then
		if not(self:IsInitialised()) then
			self:Initialise();
		end;
						
		--  Display header
		--getglobal(self.FRAME .. "Header"):SetText(ikarus.lang.profiler.HEADER);
		
		--  Save section
		getglobal(self.FRAME .. "ExportFrameHeader"):SetText(ikarus.lang.profiler.EXPORT_HEADER.."   ["..ikarus:GetProfileName().."]");
		getglobal(self.FRAME .. "ExportFrameEntryField"):SetText("");
		getglobal(self.FRAME .. "ExportFrameEntryFieldWarning"):SetText("");
		getglobal(self.FRAME .. "ExportFrameExportButton"):SetText(ikarus.lang.config.controls.EXPORT);
		
		--  Import section
		getglobal(self.FRAME .. "ImportFrameHeader"):SetText(ikarus.lang.profiler.IMPORT_HEADER);
		getglobal(self.FRAME .. "ImportFrameResolutionDropDownLabel"):SetText(ikarus.lang.profiler.IMPORT_RESOLUTION);
		getglobal(self.FRAME .. "ImportFrameImportButton"):SetText(ikarus.lang.config.controls.IMPORT);
		
		--  Delete section
		getglobal(self.FRAME .. "DeleteFrameHeader"):SetText(ikarus.lang.profiler.DELETE_HEADER);
		getglobal(self.FRAME .. "DeleteFrameDeleteButton"):SetText(ikarus.lang.config.controls.DELETE);
		
		--  Close section
		getglobal(self.FRAME .. "CloseFrameCloseButton"):SetText(ikarus.lang.config.controls.CLOSE);
				
		--  Choice Subsection in import section
		getglobal(self.FRAME .. "ImportFrameChoiceFrameCheckBox1Label"):SetText(ikarus.lang.profiler.SELECT_ALL);
		local text, frame, unit;
		for idx = 1,ikarus.profileManager.menu.MAX_UCB-1 do
			frame = getglobal(self.FRAME .. "ImportFrameChoiceFrameCheckBox".. (idx+1));
			if(ikarus.config.interface[idx]) then
				unit = ikarus.config.interface[idx][1];
				frame.unitIndex = idx;
				frame.unit = unit;
				text = ikarus.lang.config.units[unit];
				getglobal(self.FRAME .. "ImportFrameChoiceFrameCheckBox"..(idx+1).."Label"):SetText(text);
				frame:Show();
			else
				frame.unitIndex = nil;
				frame.unit = nil;
				frame:Hide();
			end;
		end;		
		
		getglobal(self.FRAME):Show();
		
		local frame = getglobal(self.FRAME.."ImportFrameDropDown");
		UIDropDownMenu_Initialize(frame, ikarus.profileManager.menu.ImportDropDownShow);
		frame = getglobal(self.FRAME.."ImportFrameResolutionDropDown");
		UIDropDownMenu_Initialize(frame, ikarus.profileManager.menu.ImportResolutionDropDownShow);
		frame = getglobal(self.FRAME.."DeleteFrameDropDown");
		UIDropDownMenu_Initialize(frame, ikarus.profileManager.menu.DeleteDropDownShow);
		
		ikarus:SetDummyState(true);
	end;
end;

function ikarus.profileManager:HideConfigFrame()
	getglobal(self.FRAME):Hide();
	self:HideUtilities();
	ikarus:SetDummyState(false);
end;

function ikarus.profileManager:HideUtilities()
	CloseDropDownMenus();
end;

--[[
	UI related stuff
	menu components and so on
]]

ikarus.profileManager.menu = {};
ikarus.profileManager.menu.MAX_UCB = 14;

function ikarus.profileManager.menu:LoadProfile(path)
	local name = string.sub(tostring(path),2);
	local prefix = string.sub(tostring(path),1,1);
	--ikarus.debug:Print(tostring(path).." "..tostring(name));
	local profile;
	if(prefix == "$") then
		--  Profile
		profile = ikarus.utils:TableClone(Ikarus_VARS[name]);
	else
		--  Preset
		local file = ikarus.constants["ADDON_DIR"] .. "profiles/"..name..".lua";
		_,profile = ikarus:LoadFile(file);
	end;
	return profile;
end;

function ikarus.profileManager.menu:ImportDropDownShow()
	local info;
	for name,profile in pairs(Ikarus_VARS) do
		if(name ~= "PROFILES" and type(profile) == "table") then
			--ikarus.debug:Print(tostring(name).." "..tostring(profile.RESOLUTION));
			info = {};
			if(profile.RESOLUTION) then
				info.text = name.." ("..profile.RESOLUTION.x.."/"..profile.RESOLUTION.y..")";
			else
				info.text = name.." (-/-)";
			end;
			info.value = "$"..name;
			info.func = ikarus.profileManager.menu.OnImportSelect;
			UIDropDownMenu_AddButton(info);
		end;
	end;
	
	for idx,config in ipairs(ikarus.profileManager.presets) do
		info = {};
		info.text = config[1].." ("..config[3].."/"..config[4]..")";
		info.textR, info.textG, info.textB = 0.96, 0.81, 0.30;
		info.value = "#"..config[2];
		info.func = ikarus.profileManager.menu.OnImportSelect;
		UIDropDownMenu_AddButton(info);
	end;
end;

function ikarus.profileManager.menu:ImportResolutionDropDownShow()
	local info;
	local displayModeCount = SYS_DispSet_GetNumDispModes();
	for i = 1, displayModeCount, 1 do
		local width = SYS_DispSet_GetDispWidth(i - 1);
		local height = SYS_DispSet_GetDispHeight(i - 1);

		info = {};
		info.text = width.."x"..height;
		info.value = {x = width, y = height};
		info.func = ikarus.profileManager.menu.OnImportResolutionSelect;
		UIDropDownMenu_AddButton(info);
	end	
end;

function ikarus.profileManager.menu:DeleteDropDownShow()
	local info;
	for name,profile in pairs(Ikarus_VARS) do
		if(name ~= "PROFILES" and type(profile) == "table") then
			info = {};
			info.text = name;
			info.value = name;
			info.func = ikarus.profileManager.menu.OnDeleteSelect;
			UIDropDownMenu_AddButton(info);
		end;
	end;
end;

function ikarus.profileManager.menu.OnImportResolutionSelect(button)
	UIDropDownMenu_SetSelectedValue(getglobal("Ikarus_ProfileManagerImportFrameResolutionDropDown"), button.value);
	getglobal("Ikarus_ProfileManagerImportFrameImportButtonResult"):SetText("");
end;

function ikarus.profileManager.menu.OnImportSelect(button)
	UIDropDownMenu_SetSelectedValue(getglobal("Ikarus_ProfileManagerImportFrameDropDown"), button.value);
	getglobal("Ikarus_ProfileManagerImportFrameImportButtonResult"):SetText("");
	local profile = ikarus.profileManager.menu:LoadProfile(button.value);
	local frame, unitConf;
	for idx = 1,ikarus.profileManager.menu.MAX_UCB-1 do
		frame = getglobal(ikarus.profileManager.FRAME .. "ImportFrameChoiceFrameCheckBox"..(idx+1));
		unitConf = ikarus.config.interface[idx];
		if(unitConf and profile[unitConf[1]]) then
			frame:Show();
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.profileManager.menu.OnDeleteSelect(button)
	UIDropDownMenu_SetSelectedValue(getglobal("Ikarus_ProfileManagerDeleteFrameDropDown"), button.value);
end;

function ikarus.profileManager.menu:OnExportButtonClick()
	local name = getglobal(ikarus.profileManager.FRAME .. "ExportFrameEntryField"):GetText();
	if(ikarus.utils:IsValidName(name)) then
		Ikarus_VARS[name] = ikarus.utils:TableClone(ikarus.profile);
	end;
end;

function ikarus.profileManager.menu:OnImportButtonClick()
	local path = UIDropDownMenu_GetSelectedValue(getglobal("Ikarus_ProfileManagerImportFrameDropDown"));
	local profile = self:LoadProfile(path);
	local imports = {};
	
	local frame;
	for idx = 2,ikarus.profileManager.menu.MAX_UCB do
		frame = getglobal(ikarus.profileManager.FRAME .. "ImportFrameChoiceFrameCheckBox"..idx);
		--ikarus.debug:Print(tostring(frame:IsVisible()).." "..tostring(frame:IsChecked()).." "..tostring(frame.unit));
		if(frame:IsVisible() and frame:IsChecked() and frame.unit) then
			imports[#imports + 1] = frame.unit;
		end;
	end;
	
	local resolution = UIDropDownMenu_GetSelectedValue(getglobal("Ikarus_ProfileManagerImportFrameResolutionDropDown"));
	
	frame = getglobal("Ikarus_ProfileManagerImportFrameImportButtonResult");
	local result = false;
	
	if(profile and resolution) then
		result = ikarus.profileManager:ImportProfile(profile, imports, resolution);
	end;
	
	if(result) then
		frame:SetText(ikarus.lang.profiler.IMPORT_FINISHED);
		frame:SetColor(0,1,0);
	else
		frame:SetText(ikarus.lang.profiler.IMPORT_FAILED);
		frame:SetColor(1,0,0);
	end;
end;

function ikarus.profileManager.menu:OnDeleteButtonClick()
	local name = UIDropDownMenu_GetSelectedValue(getglobal("Ikarus_ProfileManagerDeleteFrameDropDown"));
	if(name) then
		Ikarus_VARS[name] = nil;
	end;
	UIDropDownMenu_SetSelectedValue(getglobal("Ikarus_ProfileManagerDeleteFrameDropDown"), nil);
end;

function ikarus.profileManager.menu:OnUCBClick(button)
	getglobal("Ikarus_ProfileManagerImportFrameImportButtonResult"):SetText("");
	if not(button.unit or button.unitIndex) then
		local frame;
		for idx = 2,ikarus.profileManager.menu.MAX_UCB do
			frame = getglobal(ikarus.profileManager.FRAME .. "ImportFrameChoiceFrameCheckBox".. idx);
			if(frame:IsVisible() and frame.unit) then
				frame:SetChecked(button:IsChecked());
			end;
		end;
	end;
end;

function ikarus.profileManager.menu:OnEntryFieldValueChanged(frame)
	local name, msg = frame:GetText(), "";
	--ikarus.debug:Print(tostring(name));
	if(ikarus.utils:IsValidString(name) and Ikarus_VARS[name]) then
		msg = ikarus.lang.profiler.EXPORT_WARNING;
	end;
	
	getglobal(ikarus.profileManager.FRAME .. "ExportFrameEntryFieldWarning"):SetText(msg);
end;